package com.feituan.wx.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.feituan.core.error.SystemCode;
import com.feituan.core.exception.BusinessException;
import com.feituan.core.persistence.mapper.UserCouponMapper;
import com.feituan.core.persistence.service.ICouponService;
import com.feituan.core.persistence.service.IIntegrationUserService;
import com.feituan.core.persistence.service.IMemberCouponService;
import com.feituan.core.persistence.service.IOrderService;
import com.feituan.core.persistence.service.IRechargeRecordService;
import com.feituan.core.persistence.service.ISeqNumService;
import com.feituan.core.persistence.service.IUserCouponService;
import com.feituan.core.persistence.service.IUserService;
import com.feituan.core.pojo.entity.*;
import com.feituan.core.pojo.request.CouponAndCount;
import com.feituan.core.pojo.request.UserCouponSendReq;
import com.feituan.core.pojo.vo.Model;
import com.feituan.core.pojo.vo.ModelItem;
import com.feituan.core.service.ITypeCouponsService;
import com.feituan.core.util.DateUtils;
import com.feituan.wx.request.GoodReq;
import com.feituan.wx.request.OrderModelReq;
import com.feituan.wx.request.SubmitOrderReq;
import com.feituan.wx.vo.OrderGoodVo;
import com.feituan.wx.vo.OrderModelVo;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.service.WxPayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class OrderService {
    private final static Logger logger = LoggerFactory.getLogger(OrderService.class);
    private final static String FETCH_CODE_GENERATE_KEY = "generateFetchCode";
    @Autowired
    private IOrderService iOrderService;
    @Autowired
    private IUserService iUserService;
    @Autowired
    private ISeqNumService iSeqNumService;

    @Autowired
    private WxPayService wxPayService;

    @Resource
    private IIntegrationUserService integrationUserService;

    @Resource
    private IUserService userService;

    @Resource
    private IRechargeRecordService rechargeRecordService;

    @Resource
    private IMemberCouponService memberCouponService;

    @Resource
    private IUserCouponService userCouponService;

    @Resource
    private ICouponService couponService;

    @Autowired
    private ITypeCouponsService typeCouponsService;

    @Autowired
    private UserCouponMapper userCouponMapper;



    @Transactional
    public String submit(SubmitOrderReq req, User user, Merchant merchant, List<Product> products) {
        Order order=new Order();
        order.setPhone(req.getPhone());
        order.setCouponId(req.getCouponId());
        order.setOrderSn(generateOrderSn(user.getId()));
        order.setUserId(user.getId());
        order.setMerchantId(req.getMerchantId());
        order.setMerchantName(merchant.getName());
        order.setRoomName(req.getRoomName());
        order.setType(req.getType() == null?0: req.getType());
        order.setOrderStatus(Order.status_not_pay);
        if (order.getType() == 1) {
            order.setOrderStatus(Order.status_payed);
        }
        order.setFreightType(Order.freight_type_self);
        order.setRemark(req.getRemark());
        order.setCreateTime(Calendar.getInstance().getTime());
        BigDecimal goodsTotalPrice = new BigDecimal("0.00");


        Map<Long,Product> productMap = products.stream().collect(Collectors.toMap(Product::getId, Product->Product));
        List<OrderGoodVo> goodVos = new ArrayList<>();
        for(GoodReq goodReq : req.getProducts()){
            Product product = productMap.get(goodReq.getId());
            OrderGoodVo orderGoodVo=new OrderGoodVo();
            BeanUtils.copyProperties(product,orderGoodVo);
            orderGoodVo.setQty(goodReq.getQty());
            BigDecimal goodPrice=product.getPrice();
            if(!CollectionUtils.isEmpty(goodReq.getModelVos())){
                List<OrderModelVo> modelVos=new ArrayList<>();
                List<Model> productModels = JSON.parseArray(product.getModels(), Model.class);
                for (OrderModelReq orderModelReq :goodReq.getModelVos()){
                    ModelItem modelItem = getBy(orderModelReq.getModelIndex(), orderModelReq.getModelItemIndex(),productModels);
                    if(modelItem != null){
                        goodPrice = goodPrice.add(modelItem.getPrice());
                        OrderModelVo orderModelVo= new OrderModelVo();
                        orderModelVo.setModelIndex(orderModelReq.getModelIndex());
                        orderModelVo.setModelItemIndex(orderModelReq.getModelItemIndex());
                        orderModelVo.setName(modelItem.getName());
                        orderModelVo.setPrice(modelItem.getPrice());
                        modelVos.add(orderModelVo);
                    }
                }
                orderGoodVo.setModelVos(modelVos);
            }
            BigDecimal qty = new BigDecimal(goodReq.getQty());
            goodsTotalPrice = goodsTotalPrice
                    .add(goodPrice.multiply(qty));
            orderGoodVo.setPrice(goodPrice);
            goodVos.add(orderGoodVo);
        }
        order.setProducts(JSON.toJSONString(goodVos));

        // 订单金额
        BigDecimal orderTotalPrice = BigDecimal.ZERO;

        // 获取可用的优惠券信息 使用优惠券减免的金额
        BigDecimal couponPrice = BigDecimal.ZERO;
        Long userCouponId = req.getCouponId();
        if (userCouponId != null) {
            UserCoupon userCoupon = userCouponService.getBaseMapper().selectById(userCouponId);
            Coupon coupon = couponService.getBaseMapper().selectById(userCoupon.getCouponId());
            // 阈值
            Long threshold = coupon.getThreshold();
            // 扣减金额
            Long couponMoney = coupon.getCouponMoney();
            if (goodsTotalPrice.compareTo(new BigDecimal(threshold)) >= 0) {
                orderTotalPrice = goodsTotalPrice.subtract(new BigDecimal(couponMoney));
                couponPrice = new BigDecimal(couponMoney.toString());
            } else {
                throw new RuntimeException("商品金额不满足优惠券满减金额");
            }
        } else {
            orderTotalPrice = goodsTotalPrice;
        }

        order.setGoodsPrice(goodsTotalPrice);


        order.setCouponPrice(couponPrice);
        order.setOrderPrice(orderTotalPrice);
        if (merchant.getAutoComplete() != null && merchant.getAutoComplete() == 1) {
            order.setOrderStatus(Order.status_payed);
            order.setPayTime(Calendar.getInstance().getTime());
            order.setFetchCode(generateFetchCode());
        }
        order.setPayType(req.getPayType());
        order.setTakeFoodTime(new Date());
        iOrderService.save(order);
        return order.getOrderSn();
    }
    public ModelItem getBy(Integer modelIndex, Integer modelItemIndex,List<Model> productModels) {
        if(!CollectionUtils.isEmpty(productModels)){
            for(Model model:productModels){
                if(model.getIndex().equals(modelIndex)){
                    if(!CollectionUtils.isEmpty(model.getModelItems())){
                       return model.getModelItems().stream().filter(e->e.getIndex().equals(modelItemIndex)).findAny().orElse(null);
                    }
                }
            }
        }

        return null;
    }
    public int countByOrderSn(Long userId, String orderSn) {
        return (int) iOrderService.lambdaQuery().eq(Order::getOrderSn,orderSn).count();
    }


    public String generateOrderSn(Long userId) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMdd");
        String now = df.format(LocalDate.now());
        String orderSn = now + getRandomNum(6);
        while (countByOrderSn(userId, orderSn) != 0) {
            orderSn = getRandomNum(6);
        }
        return orderSn;
    }

    private String getRandomNum(Integer num) {
        String base = "0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < num; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    @Transactional
    public WxPayUnifiedOrderV3Result.JsapiResult prepay(Order order,HttpServletRequest request) {

        if(!order.getOrderStatus().equals(Order.status_not_pay)){
            throw new BusinessException(SystemCode.PAY_ERROR_STATUS_NOT_CORRECT);
        }
        User user = iUserService.getById(order.getUserId());
        String openid = user.getWxid();
        WxPayUnifiedOrderV3Result.JsapiResult result = null;
        try {
            WxPayUnifiedOrderV3Request  orderRequest = new WxPayUnifiedOrderV3Request();
            WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
            // 元转成分
            int fee = 0;
            BigDecimal actualPrice = order.getOrderPrice();
            fee = actualPrice.multiply(new BigDecimal(100)).intValue();
            orderRequest.setOutTradeNo(order.getOrderSn());
            amount.setTotal(fee);
            amount.setCurrency("CNY");
            orderRequest.setAmount(amount);
            orderRequest.setDescription("点餐商品");
            WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
            payer.setOpenid(openid);
            orderRequest.setPayer(payer);
            // JSAPI返回方法
            result = wxPayService.createOrderV3(TradeTypeEnum.JSAPI, orderRequest);


        } catch (Exception e) {
            logger.error("prepay fail");
            throw new BusinessException(SystemCode.PAY_PREPAY_ERROR);
        }

        return result;
    }

    /**
     * 微信付款成功或失败回调接口
     * <p>
     * 1. 检测当前订单是否是付款状态; 2. 设置订单付款成功状态相关信息; 3. 响应微信商户平台.
     *
     * @return 操作结果
     */
    @Transactional(rollbackFor = Exception.class)
    public void dtsPayNotify(WxPayNotifyV3Result.DecryptNotifyResult result) {
        // 订单编号
        String orderSn = result.getOutTradeNo();
        logger.info("回调订单号：{}", orderSn);
        String payId = result.getTransactionId();

        //判断是余额充值还是下单
        if ("CZ".equals(orderSn.substring(0, 2))) {
            logger.info("回调订单号：{}", orderSn);
            RechargeRecord rechargeRecord = rechargeRecordService.selectByNumber(orderSn);
            logger.info("订单数据：{}", rechargeRecord);
            // 分转化成元
            String totalFee = BaseWxPayResult.fenToYuan(result.getAmount().getTotal());

            // 检查支付订单金额
            if (!totalFee.equals(rechargeRecord.getPrice().toString())) {
                logger.error("微信付款成功或失败回调失败：{}", rechargeRecord.getNumber() + " : 支付金额不符合 totalFee=" + totalFee);
                throw new BusinessException(SystemCode.WX_PAY_NOTIFY_ERROR);
            }

            // 更新支付状态
            RechargeRecord record = new RechargeRecord();
            record.setId(rechargeRecord.getId());
            record.setStatus(2);
            record.setPayTime(new Date());
            record.setPayId(payId);
            rechargeRecordService.updateById(record);

            // 修改用户余额
            User userInfo = userService.selectById(rechargeRecord.getUserId());
            BigDecimal balance = userInfo.getBalance();
            if (balance == null) {
                balance = BigDecimal.ZERO;
            }

            User user = new User();
            user.setId(rechargeRecord.getUserId());
            user.setBalance(balance.add(new BigDecimal(totalFee)));
            userService.updateById(user);

            // 赠送用户优惠券
            LambdaQueryWrapper<MemberCoupon> qw = new LambdaQueryWrapper<>();
            qw.eq(MemberCoupon::getMemberAmountId, rechargeRecord.getMemberAmountId());
            List<MemberCoupon> memberCoupons = memberCouponService.getBaseMapper().selectList(qw);

            UserCouponSendReq userCouponSendReq = new UserCouponSendReq();
            userCouponSendReq.setUserIdList(Collections.singletonList(userInfo.getId()));
            List<CouponAndCount> couponAndCountList = new ArrayList<>();
            memberCoupons.forEach(el -> {
                CouponAndCount couponAndCount = new CouponAndCount();
                couponAndCount.setCouponId(el.getCouponId());
                couponAndCount.setTotal(el.getTotal());
                couponAndCountList.add(couponAndCount);
            });
            userCouponSendReq.setCouponAndCountList(couponAndCountList);
            userCouponService.sendCoupon(userCouponSendReq);
        } else {
            // 分转化成元
            String totalFee = BaseWxPayResult.fenToYuan(result.getAmount().getTotal());
            Order order = iOrderService.getBySn(orderSn);
            if (order == null) {
                logger.error("微信付款成功或失败回调失败：{}", "订单不存在 sn=" + orderSn);
                throw new BusinessException(SystemCode.WX_PAY_NOTIFY_ERROR);
            }

            // 检查这个订单是否已经处理过
            if (order.getOrderStatus().equals(Order.status_payed)) {
                logger.warn("警告：微信付款成功或失败回调：{}", "订单已经处理成功!");
                throw new BusinessException(SystemCode.WX_PAY_NOTIFY_ERROR);
            }

            // 检查支付订单金额
            if (!totalFee.equals(order.getOrderPrice().toString())) {
                logger.error("微信付款成功或失败回调失败：{}", order.getOrderSn() + " : 支付金额不符合 totalFee=" + totalFee);
                throw new BusinessException(SystemCode.WX_PAY_NOTIFY_ERROR);
            }
            Order orderUpdate = new Order();
            orderUpdate.setId(order.getId());
            orderUpdate.setOrderStatus(Order.status_payed);
            orderUpdate.setPayId(payId);
            orderUpdate.setPayTime(Calendar.getInstance().getTime());
            orderUpdate.setFetchCode(generateFetchCode());
            iOrderService.updateById(orderUpdate);

            // 新增用户积分记录
            int integration = this.roundFee(totalFee);
            if (integration == -1) {
                throw new RuntimeException();
            }
            IntegrationUser integrationUser = new IntegrationUser();
            integrationUser.setUserId(order.getUserId());
            integrationUser.setOrderId(order.getId());
            integrationUser.setIntegration(integration);
            integrationUser.setCreateTime(new Date());
            integrationUserService.saveUserIntegration(integrationUser);

            // 修改用户积分值
            User userSource = userService.selectById(order.getUserId());
            User user = new User();
            user.setId(order.getUserId());
            user.setLatestLoginTime(new Date());
            if (userSource.getIntegration() == null) {
                user.setIntegration(integration);
            } else {
                user.setIntegration(userSource.getIntegration() + integration);
            }
            userService.updateIntegration(user);

            //集星活动
//            if (integration >= 30) {
//                User userInfo = userService.selectById(user.getId());
//                if (userInfo.getStars() > 7) {
//                    userInfo.setStars(0);
//                    userService.updateById(userInfo);
//                    TypeCoupons typeCoupons = typeCouponsService.selectByType("gathering-stars");
//                    for (Coupons coupon : typeCoupons.getCoupons()) {
//                        UserCoupon userCoupon = new UserCoupon();
//                        userCoupon.setCouponId(coupon.getCouponId());
//                        userCoupon.setCreateTime(new Date());
//                        userCoupon.setUserId(user.getId());
//                        userCoupon.setCouponStatus(0);
//                        userCouponMapper.insert(userCoupon);
//                    }
//                } else {
//                    userInfo.setStars(userInfo.getStars() + 1);
//                    userService.updateById(userInfo);
//                }
//            }

            Long userCouponId = order.getCouponId();
            // 更新用户优惠券信息更新
            if (userCouponId != null) {
                UserCoupon userCoupon = userCouponService.getBaseMapper().selectById(userCouponId);
                userCoupon.setCouponStatus(1);
                userCoupon.setUseTime(new Date());
                userCouponService.getBaseMapper().updateById(userCoupon);
            }


        }



    }

    private synchronized String generateFetchCode(){
        String fieldKey = DateUtils.formatDate(Calendar.getInstance().getTime(),DateUtils.yyyyMMdd);
        return iSeqNumService.getAndSetNum(FETCH_CODE_GENERATE_KEY,fieldKey).toString();
    }

    /**
     * 支付金额转为积分
     * @param totalFee 支付金额
     * @return
     */
    public int roundFee(String totalFee) {
        try {
            double fee = Double.parseDouble(totalFee);
            return (int) Math.round(fee);
        } catch (NumberFormatException e) {
            System.err.println("输入的金额格式不正确，请确保输入的是有效的数字格式。");
            return -1; // 返回一个特殊值表示转换失败
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public String balancePayment(String orderSn) {
        // 获取订单
        Order order = iOrderService.getBySn(orderSn);
        BigDecimal orderPrice = order.getOrderPrice();
        Long userId = order.getUserId();
        Long userCouponId = order.getCouponId();
        // 用户信息
        User userSource = userService.selectById(userId);
        User user = new User();
        BigDecimal balance = userSource.getBalance(); // 余额
        Integer userIntegration = userSource.getIntegration(); // 积分
        if (balance == null) {
            balance = BigDecimal.ZERO;
        }
        if (balance.compareTo(orderPrice) < 0) {
            // 用户余额不足
            throw new RuntimeException("用户余额不足");
        }
        // 扣减用户余额
        BigDecimal newBalance = balance.subtract(orderPrice);
        user.setBalance(newBalance);
        // 更新积分数据
        int integration = this.roundFee(orderPrice.toString());
        if (integration == -1) {
            throw new RuntimeException();
        }
        IntegrationUser integrationUser = new IntegrationUser();
        integrationUser.setUserId(order.getUserId());
        integrationUser.setOrderId(order.getId());
        integrationUser.setIntegration(integration);
        integrationUser.setCreateTime(new Date());
        integrationUserService.saveUserIntegration(integrationUser);
        if (userIntegration == null) {
            userIntegration = 0;
        }
        Integer newUserIntegration = userIntegration + integration;
        user.setIntegration(newUserIntegration);
        user.setId(userId);
        userService.getBaseMapper().updateById(user);

        // 更新用户优惠券信息更新
        if (userCouponId != null) {
            UserCoupon userCoupon = userCouponService.getBaseMapper().selectById(userCouponId);
            userCoupon.setCouponStatus(1);
            userCoupon.setUseTime(new Date());
            userCouponService.getBaseMapper().updateById(userCoupon);
        }
        // 更新订单状态
        Order orderUpdate = new Order();
        orderUpdate.setId(order.getId());
        orderUpdate.setOrderStatus(Order.status_payed);
        orderUpdate.setPayTime(Calendar.getInstance().getTime());
        orderUpdate.setFetchCode(generateFetchCode());
        iOrderService.updateById(orderUpdate);

        return "支付成功";
    }
}
